///////////////////////////////////////////////////////////////////////////////
// Name:        opencv.h
// Purpose:     OpenCV API wrappers
// Copyright:   (c) 2006, Ivan Laptev, TT Solutions
// License:     GPL, Please contact us for commercial license.
//              http://www.tt-solutions.com/
///////////////////////////////////////////////////////////////////////////////
#ifndef OBJECTDET_OPENCV_H_
#define OBJECTDET_OPENCV_H_

// Boost headers
#include <boost/shared_ptr.hpp>

// TODO one day move these OpenCV headers to opencv.cpp
// OpenCV headers
#include <cv.h>
#include <cvaux.h>
#include <cvtypes.h>
#include <cxcore.h>

/**
 * OpenCV structures shared pointers
 * @{
 */
typedef boost::shared_ptr<CvFileStorage> pFileStorage;
pFileStorage guard(CvFileStorage *);

typedef boost::shared_ptr<CvMat> pMat;
pMat guard(CvMat*);
pMat guardHeader(CvMat*);

typedef std::vector<pMat> arrMat;


typedef boost::shared_ptr<IplImage> pImage;
pImage guard(IplImage*);

template<class Data>
struct DoNotDestroy { void operator() (Data*) {} };

template<class Data>
boost::shared_ptr<Data> dummyGuard(Data* data)
{
    return boost::shared_ptr<Data>(data, DoNotDestroy<Data>());
}
/**
 * @}
 */

inline
pMat ImageAsMatrix(pImage image)
{
    // this shows how OpenCV works -- two completly different types
    // such as IplImage and CvMat are treated as having the same superclass
    return dummyGuard<CvMat>(reinterpret_cast<CvMat*>(image.get()));
}


pMat CreateMat(unsigned int rows, unsigned int cols, int type);

pMat CreateMatHeader(unsigned int rows, unsigned int cols, int type);

void SetData(pMat const& arr, void* data, int step );

pMat CloneMat(pMat const&);

enum ReadWriteMode
{
    RWM_Read = 0,
    RWM_Write
};

pFileStorage OpenFileStorage(std::string const& filename, ReadWriteMode);

void WriteMatrixToFile(pFileStorage fs, std::string const& name, pMat const& mat);

pMat ReadMatrixFromFile(pFileStorage fs, std::string const& name);

void ConvertScale(pMat const& a, pMat b, double scale = 1, double shift = 0);

inline
void Convert(pMat const& a, pMat b)
{   ConvertScale(a, b); }

void Sobel(pMat const& src, pMat dst,
           int xorder, int yorder, int aperture_size = 3);

// enum values correspond exactly to OpenCV modes
enum SmoothMode
{
    Smooth_BlurNoScale = 0,
    Smooth_Blur        = 1,
    Smooth_Gaussian    = 2,
    Smooth_Median      = 3,
    Smooth_Bilateral   = 4
};

void Smooth(pMat const& src, pMat dst, SmoothMode mode = Smooth_Gaussian,
            int param1 = 3, int param2 = 0, double param3 = 0);

void* DoPtr2D(pMat const& mat, int idx0, int idx1);

// TODO ensure that const is applied correctly. Maybe provide two versions
// for read-only and read-n-write acces to the matrix data
template<typename T>
T * Ptr2D(pMat const& mat, int idx0 = 0, int idx1 = 0)
{
    return (T*)DoPtr2D(mat, idx0, idx1);
}
double GetReal2D(pMat const& mat, int idx0, int idx1);
void SetReal2D(pMat mat, int idx0, int idx1, double value);

void CopyMatrix(pMat const& src, pMat dst, pMat mask = pMat());

// TODO make code to be a enum
void CvtColor(pMat const& src, pMat const& dst, int code);

void Multiply(pMat const& src1, pMat const& src2, pMat dst,
                    double scale = 1);

void MatrixMultiply(pMat const& src1, pMat const& src2, pMat dst);

void Divide(pMat const& src1, pMat const& src2, pMat dst, double scale = 1);

void GEMM(pMat const& src1, pMat const& src2, double alpha,
          pMat const& src3, double beta,
          pMat dst, int tABC = 0);

enum ResizeMode
{
    Resize_InterNN     = 0,
    Resize_InterLinear = 1,
    Resize_InterCubic  = 2,
    Resize_InterArea   = 3
};

void Resize(pMat const& src, pMat dst, ResizeMode interpolation = Resize_InterLinear);

void SetValue(pMat const& arr, CvScalar const& value, pMat const mask = pMat());

void PowerMatrix(pMat const& src, pMat dst, double power);

void Merge(pMat const& src0, pMat const& src1, pMat const& src2, pMat const& src3,
           pMat dst);

void FlipMatrix(pMat const& src, pMat dst = pMat(), int flip_mode = 0);

#endif // OBJECTDET_OPENCV_H_

